home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_540 / browser / browserii_src.lzh / Copy.c < prev    next >
C/C++ Source or Header  |  1991-07-28  |  20KB  |  612 lines

  1. /*
  2.  *    Copy.c - Copyright © 1991 by S.R. & P.C.
  3.  *
  4.  *    Created:    02 Mar 1991  15:50:36
  5.  *    Modified:    20 Jul 1991  12:25:40
  6.  *
  7.  *    Make>> make
  8.  */
  9.  
  10. #include "Global.h"
  11. #include "FileList.h"
  12. #include "Actions.h"
  13. #include "ActionBack.h"
  14. #include "Process.h"
  15. #include "proto/Copy.h"
  16. #include "proto/Actions.h"
  17. #include "proto/ActionBack.h"
  18. #include "proto/Request.h"
  19. #include "proto/File.h"
  20. #include "proto/FileList.h"
  21.  
  22.  
  23. extern struct ExecBase *SysBase;
  24. extern char *ReqTitle;
  25.  
  26.  
  27. #define BUFFSIZEUNIT            11528
  28. #define MAXBUFFER_MOUNTED        200000
  29. #define MAXBUFFER_UNMOUNTED        902000
  30.  
  31.  
  32. /*
  33.  *    Compute how many buffers max will be used for this copy. If destination volume
  34.  *    and one of sources volumes are mounted, MAXBUFFER_MOUNTED memory will be used.
  35.  *    Else, MAXBUFFER_UNMOUNTED which is bigger will be used to minimize disk swapping.
  36.  */
  37.  
  38. static void InitMaxBuf(struct HeadFileList *hfl)
  39. {
  40.     struct BrowserDir *bd, *nextbd;
  41.     struct InfoData *info;
  42.     struct Process *pp;
  43.     APTR WindowPtr;
  44.  
  45.     if (!(info = AllocMem(sizeof(struct InfoData), MEMF_PUBLIC|MEMF_CLEAR)))
  46.         return;
  47.     pp = (struct Process *)SysBase->ThisTask;
  48.     WindowPtr = pp->pr_WindowPtr;
  49.     pp->pr_WindowPtr = (APTR)-1L;
  50.     hfl->MaxBuffer = MAXBUFFER_UNMOUNTED;
  51.     /* Info() needs volume referenced by the lock to be mounted. If Info() fails, volume is not mounted */
  52.     if (Info(hfl->DestDir, info)) {
  53.         bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
  54.         while(nextbd = (struct BrowserDir *)bd->Node.mln_Succ) {
  55.             if (Info(bd->DirLock, info)) {
  56.                 hfl->MaxBuffer = MAXBUFFER_MOUNTED;
  57.                 break;
  58.             }
  59.             bd = nextbd;
  60.         }
  61.     }
  62.     pp->pr_WindowPtr = WindowPtr;
  63.     FreeMem(info, sizeof(struct InfoData));
  64. }
  65.  
  66.  
  67. static BOOL Mem(struct HeadFileList *hfl, long AskSize)
  68. {
  69.     long AfterUse;
  70.     long Avail;
  71.  
  72.     if (hfl->ActualUse + AskSize > hfl->MaxBuffer)
  73.         return FALSE;
  74.     Avail = AvailMem(MEMF_PUBLIC);
  75.     /* Never use more than 80% of initial available mem, and allways leave at least 15 KB free */
  76.     AfterUse = hfl->StartMem - Avail - AskSize;
  77.     if (Avail < BUFFSIZEUNIT+5000 || hfl->StartMem * 8 < AfterUse * 10)
  78.         return FALSE;
  79.     return TRUE;
  80. }
  81.  
  82.  
  83. /* Copy Quick handling routine. Skip file if older than existing one. If return TRUE, file must be copied */
  84.  
  85. static BOOL CheckDest(BPTR DestDir, struct SuperFileInfo *sfi)
  86. {
  87.     struct FileInfoBlock *fib;
  88.     BPTR CD;
  89.     BOOL ret = TRUE;
  90.  
  91.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  92.         return FALSE;
  93.     CD = CurrentDir(DestDir);
  94.     if (GetFib(sfi->FileInfo.fi_Name, fib, FALSE) == A_RETRY) {
  95.         if (Date2Secs(&fib->fib_Date) >= sfi->FileInfo.fi_Secs) {
  96.              sfi->Flags |= SFI_REMOVE|SFI_NOSELECT;
  97.              ret = FALSE;
  98.         }
  99.     }
  100.     CurrentDir(CD);
  101.     FreeMem(fib, sizeof(struct FileInfoBlock));
  102.     return ret;
  103. }
  104.  
  105.  
  106. /* Obtain lock on destination directory if exists */
  107.  
  108. static short GetDestDir(BPTR DestDir, struct SuperFileInfo *sfi)
  109. {
  110.     struct FileInfoBlock *fib;
  111.     BPTR CD, DirLock;
  112.     char *Name;
  113.     short Ok = A_RETRY;
  114.  
  115.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  116.         return A_STOP;
  117.     CD = CurrentDir(DestDir);
  118.     Name = sfi->FileInfo.fi_Name;
  119.     while(Ok == A_RETRY && (DirLock = Lock(Name, ACCESS_READ))) {
  120.         while (Ok == A_RETRY && !Examine(DirLock, fib))
  121.             Ok = ThreeGadRequest("Retry", "Skip", "Couldn't get info for \"%s\"\n%s.", Name, StrIoErr());
  122.         if (Ok == A_RETRY) {
  123.             if (fib->fib_DirEntryType > 0) {
  124.                 Fib2Fi(&sfi->FileInfo, fib);    /* get info from dest dir for action back */
  125.                 break;
  126.             }                
  127.             else {
  128.                 UnLock(DirLock);
  129.                 Ok = ThreeGadRequest("Retry", "Skip", "Can't create dir \"%s\"\nA file already exists.", Name);
  130.                 if (Ok != A_RETRY) {
  131.                     sfi->Flags |= SFI_REMOVE;
  132.                     DirLock = NULL;
  133.                 }
  134.             }
  135.         }
  136.     }
  137.     FreeMem(fib, sizeof(struct FileInfoBlock));
  138.     sfi->FileDir.Dir.DestDir = DirLock;
  139.     CurrentDir(CD);
  140.     return Ok;
  141. }
  142.  
  143.  
  144. static short HandleCopyFlags(struct SuperFileInfo *sfi, struct FileInfoBlock *fib, UBYTE CopyFlags)
  145. {
  146.     char *Name;
  147.     short Ok = A_RETRY;
  148.  
  149.     Name = sfi->FileInfo.fi_Name;
  150.     if (CopyFlags & (CF_CLONE|CF_DATE))
  151.         Ok = Touch(Name, &sfi->FileInfo.fi_Date);
  152.     if (Ok == A_RETRY && CopyFlags & (CF_CLONE|CF_PROTECT))
  153.         Ok = Protect(Name, sfi->FileInfo.fi_Protection & ~FIBF_ARCHIVE);
  154.     if (Ok == A_RETRY && CopyFlags & (CF_CLONE|CF_COMMENT))
  155.         Ok = Comment(Name, sfi->FileInfo.fi_Comment);
  156.     if (Ok == A_RETRY && (Ok = GetFib(Name, fib, TRUE) == A_RETRY))
  157.         Fib2Fi(&sfi->FileInfo, fib);
  158.     if (Ok == A_RETRY)
  159.         sfi->ActionBack |= AB_NEW_ENTRY;
  160.     return Ok;
  161. }
  162.  
  163.  
  164. /* Try to obtain destination directory. If doesn't exists, create it */
  165.  
  166. static short MakeDestDir(struct SuperFileInfo *sfi, struct FileInfoBlock *fib, UBYTE CopyFlags, UBYTE CopyMode)
  167. {
  168.     BPTR CurrentDir, DirLock;
  169.     char *Name;
  170.     short Ok = A_RETRY;
  171.  
  172.     if (sfi->FileDir.Dir.DestDir)
  173.         return A_RETRY;
  174.     CurrentDir = ((struct Process *)SysBase->ThisTask)->pr_CurrentDir;
  175.     if (sfi->FileInfo.fi_Type == DLX_DIR && (CopyMode & CM_COPY_HIERARCHY)) {
  176.         if ((Ok = GetDestDir(CurrentDir, sfi)) == A_RETRY) { 
  177.             if (!sfi->FileDir.Dir.DestDir) {
  178.                 /* dir doesn't exist so, create it */
  179.                 Name = sfi->FileInfo.fi_Name;
  180.                 while(Ok == A_RETRY && !(DirLock = CreateDir(Name)))
  181.                     Ok = ThreeGadRequest("Retry", "Skip", "Couldn't create dir \"%s\"\n%s.", Name, StrIoErr());
  182.                 if (Ok == A_RETRY) {
  183.                     /* replace the ACCESS_WRITE lock given by CreateDir() by an ACCESS_READ lock so people can access it */
  184.                     UnLock(DirLock);
  185.                     DirLock = NULL;
  186.                     Ok = HandleCopyFlags(sfi, fib, CopyFlags);
  187.                     while(Ok == A_RETRY && !(DirLock = Lock(Name, ACCESS_READ)))
  188.                         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", Name, StrIoErr());
  189.                 }
  190.                 sfi->FileDir.Dir.DestDir = DirLock;
  191.             }
  192.         }
  193.     }
  194.     else /* volumes, devices, assigns, or don't copy hierarchy */
  195.         sfi->FileDir.Dir.DestDir = DupLock(CurrentDir);
  196.     return Ok;
  197. }
  198.  
  199.  
  200. static short PurgeBuffer(struct SuperFileInfo *sfi)
  201. {
  202.     struct BufferList *Cur;
  203.     char *Buffer;
  204.     long ToBeWritten;
  205.     short Ok = A_RETRY;
  206.  
  207.     while(Ok == A_RETRY && (Cur = sfi->FileDir.File.BufferList)) {
  208.         sfi->FileDir.File.BufferList = Cur->Next;
  209.         ToBeWritten = Cur->Size;
  210.         Buffer = Cur->Memory;
  211.         while(Ok == A_RETRY && (ToBeWritten -= Write(sfi->FileDir.File.FH_D, Buffer, ToBeWritten)) != 0) {
  212.             Buffer = Cur->Memory + Cur->Size - ToBeWritten;
  213.             Ok = ThreeGadRequest("Retry", "Skip", "Error writing \"%s\"\n%s.", sfi->FileInfo.fi_Name, StrIoErr());
  214.         }
  215.         FreeMem(Cur, Cur->Size+sizeof(struct BufferList));
  216.     }
  217.     return Ok;
  218. }
  219.  
  220.  
  221. static short WriteFile(struct SuperFileInfo *sfi, struct FileInfoBlock *fib, UBYTE CopyFlags, UBYTE CopyMode)
  222. {
  223.     BPTR FileLock;
  224.     char *Name;
  225.     short Ok = A_RETRY;
  226.  
  227.     Name = sfi->FileInfo.fi_Name;
  228.     if ((sfi->ActionBack & AB_DELETE_DEST) && sfi->FileDir.File.FH_D) {
  229.         Close(sfi->FileDir.File.FH_D);
  230.         sfi->FileDir.File.FH_D = NULL;
  231.         DeleteDest(Name);
  232.     }
  233.     if (sfi->FileDir.File.BufferList) {
  234.         if (!sfi->FileDir.File.FH_D) {
  235.             if ((CopyMode & (CM_ASK_OVERWRITE|CM_DONT_OVERWRITE)) && (FileLock = Lock(Name, ACCESS_READ))) {
  236.                 UnLock(FileLock);
  237.                 if (CopyMode & CM_DONT_OVERWRITE) {
  238.                     Ok = A_SKIP;
  239.                     sfi->Flags |= SFI_REMOVE|SFI_NOSELECT;
  240.                 }
  241.                 else if (!TwoGadRequest(ReqTitle, "File \"%s\" already exists\nOverwrite it ?", Name))
  242.                     Ok = A_SKIP;
  243.             }
  244.             while (Ok == A_RETRY && !(sfi->FileDir.File.FH_D = Open(Name, MODE_NEWFILE)))
  245.                 Ok = ThreeGadRequest("Retry", "Skip", "Couldn't open \"%s\" for writing\n%s.", Name, StrIoErr());
  246.         }
  247.         if (Ok != A_RETRY)
  248.             sfi->Flags |= SFI_REMOVE;
  249.         else if ((Ok = PurgeBuffer(sfi)) != A_RETRY) {
  250.             sfi->FileDir.File.ToBeRead = 0;    /* something wrong happened, so don't continue reading ! */
  251.             Close(sfi->FileDir.File.FH_D);
  252.             sfi->FileDir.File.FH_D = NULL;
  253.             sfi->Flags |= SFI_REMOVE;
  254.             if (TwoGadRequest(ReqTitle, "File \"%s\" couldn't be copied\nDelete bad copy ?", Name))
  255.                 DeleteDest(Name);
  256.         }
  257.         else if (sfi->Flags & SFI_READ_FINISHED) {
  258.             Close(sfi->FileDir.File.FH_D);    /* close if nothing else must be read */
  259.             sfi->FileDir.File.FH_D = NULL;
  260.             Ok = HandleCopyFlags(sfi, fib, CopyFlags);
  261.         }
  262.         FreeFileBuffers(sfi);
  263.     }
  264.     return Ok;
  265. }
  266.  
  267.  
  268. static short WriteDir(struct HeadFileList *hfl, struct SuperFileInfo *StartSFI, struct FileInfoBlock *fib);
  269.  
  270. static short WriteEntry(struct HeadFileList *hfl, struct SuperFileInfo *sfi, struct FileInfoBlock *fib)
  271. {
  272.     short Ok = A_RETRY;
  273.     BPTR CD;
  274.  
  275.     if ((sfi->FileInfo.fi_Type != DLX_FILE) && (sfi->Flags & (SFI_READING|SFI_READ_FINISHED))) {
  276.         if ((Ok = MakeDestDir(sfi, fib, hfl->CopyFlags, hfl->CopyMode)) == A_RETRY) {
  277.             CD = CurrentDir(sfi->FileDir.Dir.DestDir);
  278.             Ok = WriteDir(hfl, sfi, fib);
  279.             CurrentDir(CD);
  280.         }
  281.         else
  282.             sfi->Flags |= SFI_REMOVE;
  283.     }
  284.     else
  285.         Ok = WriteFile(sfi, fib, hfl->CopyFlags, hfl->CopyMode);
  286.     return Ok;
  287. }
  288.  
  289.  
  290. static short WriteDir(struct HeadFileList *hfl, struct SuperFileInfo *StartSFI, struct FileInfoBlock *fib)
  291. {
  292.     struct SuperFileInfo *sfi, *nextsfi;
  293.     short Ok = A_RETRY;
  294.  
  295.     sfi = (struct SuperFileInfo *)StartSFI->FileDir.Dir.SuperFileList.mlh_Head;
  296.     while(Ok != A_STOP && (nextsfi = (struct SuperFileInfo *)sfi->Node.mln_Succ)) {
  297.         Ok = WriteEntry(hfl, sfi, fib);
  298.         if (sfi->Flags & (SFI_READ_FINISHED|SFI_REMOVE)) {
  299.             if (sfi->Flags & SFI_REMOVE && !(sfi->Flags & SFI_NOSELECT))
  300.                 sfi->ActionBack = (sfi->ActionBack & ~AB_DESELECT) | AB_SELECT;
  301.             SendActionBack(sfi, StartSFI->FileDir.Dir.SrcDir, StartSFI->FileDir.Dir.DestDir);
  302.             if (!(sfi->Flags & SFI_READING)) {
  303.                 Remove((struct Node *)sfi);
  304.                 FreeSuperFileInfo(sfi, NULL, NULL);
  305.             }
  306.         }
  307.         if (Ok != A_RETRY)
  308.             hfl->CopySuccessfull = FALSE;
  309.         sfi = nextsfi;
  310.     }
  311.     if ((StartSFI->Flags & SFI_READ_FINISHED) && (hfl->CopyMode & CM_COPY_HIERARCHY))
  312.         SendUpdateDir(StartSFI->FileDir.Dir.DestDir);
  313.     return Ok;
  314. }
  315.  
  316.  
  317. static short WriteFileList(struct HeadFileList *hfl)
  318. {
  319.     struct FileInfoBlock *fib;
  320.     struct SuperFileInfo *sfi, *nextsfi;
  321.     struct BrowserDir *bd;
  322.     short Ok = A_RETRY;
  323.     BPTR CD;
  324.     BOOL Duplicate;
  325.  
  326.     /* if hfl->NewName isn't empty, the action is Duplicate, else Copy */
  327.     Duplicate = (hfl->ActionArgs.NewName[0]) ? TRUE : FALSE;
  328.     /* Allocate a fib for WriteFile() to examine dest file */
  329.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  330.         return A_STOP;
  331.     CD = CurrentDir(hfl->DestDir);
  332.     bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
  333.     while(Ok != A_STOP && bd->Node.mln_Succ) {
  334.         if (Duplicate && bd->DirLock)
  335.             CurrentDir(bd->DirLock);
  336.         sfi = (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
  337.         while(Ok != A_STOP && (nextsfi = (struct SuperFileInfo *)sfi->Node.mln_Succ)) {
  338.             if ((Ok = WriteEntry(hfl, sfi, fib)) != A_RETRY)
  339.                 hfl->CopySuccessfull = FALSE;
  340.             if ((sfi->Flags & SFI_REMOVE) || (sfi->Flags & SFI_READ_FINISHED) && !(hfl->CopyMode & CM_ALLWAYS_MOVE)) {
  341.                 if (sfi->Flags & SFI_REMOVE && !(sfi->Flags & SFI_NOSELECT))
  342.                     sfi->ActionBack = (sfi->ActionBack & ~AB_DESELECT) | AB_SELECT;
  343.                 SendActionBack(sfi, bd->DirLock, (Duplicate) ? bd->DirLock : hfl->DestDir);
  344.             }
  345.             if ((sfi->Flags & SFI_REMOVE) && !(sfi->Flags & SFI_READING)) {
  346.                 Remove((struct Node *)sfi);
  347.                 FreeSuperFileInfo(sfi, NULL, NULL);
  348.             }
  349.             sfi = nextsfi;
  350.         }
  351.         if (Duplicate)
  352.             SendUpdateDir(bd->DirLock);
  353.         bd = (struct BrowserDir *)bd->Node.mln_Succ;
  354.     }
  355.     FreeMem(fib, sizeof(struct FileInfoBlock));
  356.     CurrentDir(CD);
  357.     /* ok, memory released now */
  358.     hfl->StartMem = AvailMem(MEMF_PUBLIC);    /* reset the base mem */
  359.     hfl->ActualUse = 0;
  360.     return Ok;
  361. }
  362.  
  363.  
  364. static short Read2Buffer(struct HeadFileList *hfl, struct SuperFileInfo *sfi, struct BufferList **bl)
  365. {
  366.     char *Buffer;
  367.     long ToBeRead, size;
  368.     short Ok = A_RETRY;
  369.  
  370.     size = (sfi->FileDir.File.ToBeRead > BUFFSIZEUNIT) ? BUFFSIZEUNIT : sfi->FileDir.File.ToBeRead;
  371.     if (!Mem(hfl, size+sizeof(struct BufferList)))
  372.         return -1;    /* Mem() say there is not enough memory */
  373.     if (!(*bl = AllocMem(size+sizeof(struct BufferList), MEMF_PUBLIC)))
  374.         return -1;    /* Can't alloc buffer, so return a mem error */
  375.     ToBeRead = (*bl)->Size = size;
  376.     (*bl)->Next = NULL;
  377.     Buffer = (*bl)->Memory;
  378.     while(Ok == A_RETRY && (ToBeRead -= Read(sfi->FileDir.File.FH_S, Buffer, ToBeRead)) != 0) {
  379.         Buffer = (*bl)->Memory + size - ToBeRead;
  380.         Ok = ThreeGadRequest("Retry", "Skip", "Error reading \"%s\"\n%s.", sfi->FileInfo.fi_Name, StrIoErr());
  381.     }
  382.     sfi->FileDir.File.ToBeRead -= size;
  383.     hfl->ActualUse += size+sizeof(struct BufferList);
  384.     return Ok;
  385. }
  386.  
  387.  
  388. static short CopyFile(struct HeadFileList *hfl, struct SuperFileInfo *sfi)
  389. {
  390.     struct BufferList **CBL = NULL;
  391.     char *Name;
  392.     short Ok = A_RETRY;
  393.  
  394.     Name = sfi->OldName;
  395.     while (Ok == A_RETRY && !(sfi->FileDir.File.FH_S = Open(Name, MODE_OLDFILE)))
  396.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't open \"%s\" for reading\n%s.", Name, StrIoErr());
  397.     if (Ok == A_RETRY) {
  398.         sfi->Flags |= SFI_READING;
  399.         sfi->FileDir.File.ToBeRead = sfi->FileInfo.fi_Size;
  400.         CBL = &sfi->FileDir.File.BufferList;
  401.         while(Ok == A_RETRY && sfi->FileDir.File.ToBeRead) {
  402.             switch(Ok = Read2Buffer(hfl, sfi, CBL)) {
  403.             case -1:
  404.                 if (hfl->ActualUse == 0)
  405.                     Ok = A_STOP;    /* Not enough memory for Copy */
  406.                 else
  407.                     Ok = WriteFileList(hfl);
  408.                 CBL = &(sfi->FileDir.File.BufferList);    /* reset the mem ptr: return to beginning */
  409.                 break;
  410.             case A_RETRY:
  411.                 CBL = &(*CBL)->Next;
  412.                 break;
  413.             default:    /* Skip or Cancel */
  414.                 sfi->ActionBack = AB_SELECT|AB_DELETE_DEST;
  415.                 FreeFileBuffers(sfi);        /* free memory used by this file */
  416.                 /* now recompute ActualUse. This not really valid since number_of_buffer * sizeof(struct BufferList) is lost,
  417.                  * but as we don't know the number of buffers, it better than loosing everything! */
  418.                 hfl->ActualUse -= sfi->FileInfo.fi_Size - sfi->FileDir.File.ToBeRead;
  419.                 hfl->CopySuccessfull = FALSE;
  420.             }
  421.         }
  422.         Close(sfi->FileDir.File.FH_S);
  423.         sfi->FileDir.File.FH_S = NULL;
  424.         sfi->Flags = (sfi->Flags & ~SFI_READING) | SFI_READ_FINISHED;
  425.     }
  426.     else
  427.         sfi->Flags |= SFI_REMOVE;
  428.     return Ok;
  429. }
  430.  
  431.  
  432. static short CopyDir(struct HeadFileList *hfl, struct SuperFileInfo *StartSFI, struct FileInfoBlock *StartFib)
  433. {
  434.     struct SuperFileInfo *sfi;
  435.     struct FileInfoBlock *fib;
  436.     BPTR CD, DirLock;
  437.     char *Name;
  438.     BOOL NoCheck = FALSE;    /* Copy Quick handling. If dest dir don't exists yet, no use to check for presence of a file in it! */
  439.     short err, Ok = A_RETRY;
  440.  
  441.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  442.         return A_STOP;
  443.     if ((hfl->CopyMode & CM_UPDATE) && !StartSFI->FileDir.Dir.DestDir)
  444.         NoCheck = TRUE;
  445.     Name = StartSFI->OldName;
  446.     while(Ok == A_RETRY && !(DirLock = Lock(Name, ACCESS_READ)))
  447.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", Name, StrIoErr());
  448.     if (Ok != A_RETRY) {
  449.         StartSFI->Flags |= SFI_REMOVE;
  450.         StartSFI->ActionBack = AB_SELECT;
  451.     }
  452.     else {
  453.         StartSFI->FileDir.Dir.SrcDir = DirLock;
  454.         CD = CurrentDir(DirLock);
  455.         NewMinList(&StartSFI->FileDir.Dir.SuperFileList);
  456.         *fib = *StartFib;
  457.         StartSFI->Flags |= SFI_READING|SFI_DIREMPTY;
  458.         while (Ok != A_STOP && ExNext(DirLock, fib)) {
  459.             if (sfi = AllocMem(sizeof(struct SuperFileInfo), MEMF_PUBLIC|MEMF_CLEAR)) {
  460.                 Ok = A_RETRY;
  461.                 Fib2Fi(&sfi->FileInfo, fib);
  462.                 if (!(hfl->Select.si_Flags & SI_AFFECT_SUBDIRS) || MatchFilters(&sfi->FileInfo, &hfl->Select)) {
  463.                     /* link file to current dir filelist */
  464.                     AddTail((struct List *)&StartSFI->FileDir.Dir.SuperFileList, (struct Node *)sfi);
  465.                     strcpy(sfi->OldName, sfi->FileInfo.fi_Name);
  466.                     if (sfi->FileInfo.fi_Type == DLX_FILE) {
  467.                         if (!(hfl->CopyMode & CM_UPDATE) || NoCheck || CheckDest(StartSFI->FileDir.Dir.DestDir, sfi))
  468.                             Ok = CopyFile(hfl, sfi);
  469.                     }
  470.                     else {
  471.                         if (hfl->CopyMode & CM_UPDATE)
  472.                             Ok = GetDestDir(StartSFI->FileDir.Dir.DestDir, sfi);
  473.                         if (Ok == A_RETRY && !(sfi->Flags & SFI_REMOVE))
  474.                             Ok = CopyDir(hfl, sfi, fib);
  475.                     }
  476.                     if (Ok == A_RETRY && !(sfi->Flags & SFI_DIREMPTY))
  477.                         StartSFI->Flags &= ~SFI_DIREMPTY;
  478.                     if (sfi->Flags & SFI_REMOVE) {
  479.                         /* no dest dir for action back here, file wasn't written */
  480.                         if (!(sfi->Flags & SFI_NOSELECT))
  481.                             sfi->ActionBack = (sfi->ActionBack & ~AB_DESELECT) | AB_SELECT;
  482.                         Remove((struct Node *)sfi);
  483.                         FreeSuperFileInfo(sfi, DirLock, NULL);
  484.                     }
  485.                 }
  486.                 else {
  487.                     CleanFileInfo(&sfi->FileInfo);
  488.                     FreeMem(sfi, sizeof(struct SuperFileInfo));
  489.                 }
  490.             }
  491.             else
  492.                 Ok = A_STOP;
  493.         }
  494.         if (Ok == A_RETRY && (err = IoErr()) != ERROR_NO_MORE_ENTRIES)
  495.             Ok = ThreeGadRequest("Skip", NULL, "Error reading directory \"%s\"\n%s.", Name, DosError(err)) << 1;
  496.         if (!(hfl->CopyMode & CM_COPY_EMPTYDIRS) && (StartSFI->Flags & SFI_DIREMPTY))
  497.             StartSFI->Flags |= SFI_REMOVE;
  498.         CurrentDir(CD);
  499.     }
  500.     if (Ok != A_RETRY)
  501.         hfl->CopySuccessfull = FALSE;
  502.     StartSFI->Flags = (StartSFI->Flags & ~SFI_READING) | SFI_READ_FINISHED;
  503.     FreeMem(fib, sizeof(struct FileInfoBlock));
  504.     return Ok;
  505. }
  506.  
  507.  
  508. static short MoveFile(struct SuperFileInfo *sfi, BPTR DestDir)
  509. {
  510.     short Ok = A_RETRY;
  511.     char *OldName, *NewName;
  512.     char Buffer[300];
  513.  
  514.     OldName = sfi->FileInfo.fi_Name;
  515.     PathName(DestDir, Buffer, 255);
  516.     /* remove volume name from path to avoid disk confusion if two volumes have the same name */
  517.     NewName = Buffer;
  518.     while(*NewName && *NewName != ':') NewName++;
  519.     TackOn(NewName, OldName);
  520.     while(Ok == A_RETRY && !Rename(OldName, NewName))
  521.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't move \"%s\"\n%s.", OldName, StrIoErr());
  522.     if (Ok == A_RETRY)
  523.         sfi->ActionBack |= (AB_DELETE_SOURCE|AB_NEW_ENTRY);
  524.     else
  525.         sfi->ActionBack = AB_SELECT;
  526.     return Ok;
  527. }
  528.  
  529.  
  530. void CopyMove(struct HeadFileList *hfl)
  531. {
  532.     struct FileInfoBlock *fib;
  533.     struct SuperFileInfo *sfi, *nextsfi;
  534.     struct BrowserDir *bd, *nextbd;
  535.     BOOL Duplicate;
  536.     short Ok = A_RETRY;
  537.  
  538.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  539.         return;
  540.     Duplicate = (hfl->ActionArgs.NewName[0]) ? TRUE : FALSE;
  541.     /* init some global var for test mem use */
  542.     hfl->StartMem = AvailMem(MEMF_PUBLIC);    /* init base mem */
  543.     hfl->ActualUse = 0;
  544.     hfl->CopySuccessfull = TRUE;
  545.     InitMaxBuf(hfl);
  546.  
  547.     bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
  548.     while(Ok != A_STOP && (nextbd = (struct BrowserDir *)bd->Node.mln_Succ)) {
  549.         if (bd->DirLock)
  550.             CurrentDir(bd->DirLock);
  551.         sfi = (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
  552.         if (!(hfl->CopyMode & CM_ALLWAYS_COPY) && bd->RootLock && !CompareLock(bd->RootLock, hfl->DestRoot)) {
  553.             while(Ok != A_STOP && (nextsfi = (struct SuperFileInfo *)sfi->Node.mln_Succ)) {
  554.                 Ok = MoveFile(sfi, hfl->DestDir);
  555.                 SendActionBack(sfi, bd->DirLock, hfl->DestDir);
  556.                 sfi = nextsfi;
  557.             }
  558.             Remove((struct Node *)bd);
  559.             FreeBrowserDir(bd, NULL);
  560.         }
  561.         else {
  562.             while(Ok != A_STOP && (nextsfi = (struct SuperFileInfo *)sfi->Node.mln_Succ)) {
  563.                 if ((Ok = GetFib(sfi->FileInfo.fi_Name, fib, TRUE)) == A_RETRY) {
  564.                     /* Don't Fib2Fi() for a device, volume or assign. It removes
  565.                      * ending colon from name */
  566.                     if (sfi->FileInfo.fi_Type == DLX_FILE || sfi->FileInfo.fi_Type == DLX_DIR)
  567.                         Fib2Fi(&sfi->FileInfo, fib);
  568.                 }
  569.                 if (Ok == A_RETRY && Duplicate)
  570.                     Ok = MakeNewName(sfi->FileInfo.fi_Name, hfl->ActionArgs.NewName, sfi->OldName);
  571.                 if (Ok == A_RETRY) {
  572.                     switch(sfi->FileInfo.fi_Type) {
  573.                     case DLX_FILE:
  574.                         if (!(hfl->CopyMode & CM_UPDATE) || CheckDest((Duplicate) ? bd->DirLock : hfl->DestDir, sfi))
  575.                             Ok = CopyFile(hfl, sfi);
  576.                         break;
  577.                     case DLX_DIR:
  578.                         if (hfl->CopyMode & CM_UPDATE)
  579.                             Ok = GetDestDir(hfl->DestDir, sfi);
  580.                         if (Ok == A_RETRY && !(sfi->Flags & SFI_REMOVE))
  581.                             Ok = CopyDir(hfl, sfi, fib);
  582.                         break;
  583.                     default:        /* Volume, Device, or Assign */
  584.                         Ok = CopyDir(hfl, sfi, fib);
  585.                     }
  586.                 }
  587.                 if (sfi->Flags & SFI_REMOVE) {
  588.                     /* no dest dir for action back here, file wasn't written */
  589.                     if (!(sfi->Flags & SFI_NOSELECT))
  590.                         sfi->ActionBack = (sfi->ActionBack & ~AB_DESELECT) | AB_SELECT;
  591.                     Remove((struct Node *)sfi);
  592.                     FreeSuperFileInfo(sfi, bd->DirLock, NULL);
  593.                 }
  594.                 sfi = nextsfi;
  595.             }
  596.         }
  597.         bd = nextbd;
  598.     }
  599.     FreeMem(fib, sizeof(struct FileInfoBlock));
  600.     if (Ok != A_STOP)
  601.         Ok = WriteFileList(hfl);
  602.     if (Ok != A_STOP && (hfl->CopyMode & CM_ALLWAYS_MOVE)) {
  603.         if (!hfl->CopySuccessfull)
  604.             Ok = TwoGadRequest(ReqTitle, "One or more file(s) not copied\nDelete source(s) anyway ?");
  605.         if (Ok != A_STOP)
  606.             DoAction(hfl, BROWSERACTION_DELETE);
  607.     }
  608.     CurrentDir(((struct TaskData *)SysBase->ThisTask->tc_UserData)->td_InitialDir);
  609. }
  610.  
  611.  
  612.